共计 6440 个字符,预计需要花费 17 分钟才能阅读完成。
提醒:本文最后更新于 2024-08-26 17:31,文中所关联的信息可能已发生改变,请知悉!
效果
可以看到,大部分白色噪声都被去除,只有部分连块的“较大”噪声没有去除。不过我们暂时可以不用管它,因为只需要多次利用该算法(如果遇到仍无法解决的情况,那么再附加“缩小二分之一”图像的检测就可以了)
考虑该算法是否合理
这里考虑的条件仅为是否会对直线检测造成影响(直线检测算法暂时利用 opencv 中的 canny 算子)
下面是降噪前和降噪后的样例:
降噪前
降噪后
旧算法降噪后
首先新算法降噪前后,对 canny 检测几乎没有影响,甚至还有一定程度的提升
但旧的算法会使边缘变得不平滑,这体现出了新算法的优势之一
噪声条件更加恶劣
噪声值也为随机时
可以看出效果不错
代码
# python3.8
# utf-8
"""
1. 找出噪声点:新划分方法
标记次数
2. 修改
找最接近的未标记过的点
"""
import cv2 as cv
import numpy as np
threshold = 1
class PixelChannel:
def __init__(self, channel, noise, row, col):
self.noise = noise
self.channel = channel
self.row = row
self.col = col
class Part:
def __init__(self, x, y, area):
self.x = x
self.y = y
self.area = area
# 建立像素通道类
def create_pixel_channel(img_channel):
(row, col) = img_channel.shape
result = PixelChannel(img_channel, noise_check(img_channel), row, col)
return result
# 一维数组映射到二维
def _1d_2_2d(x):
if x == 0:
return 0, 0
elif x == 1:
return 0, 1
elif x == 2:
return 0, 2
elif x == 3:
return 1, 2
elif x == 4:
return 2, 2
elif x == 5:
return 2, 1
elif x == 6:
return 2, 0
elif x == 7:
return 1, 0
def division1(_8area):
result = [0] * 8
p1 = [_8area[0][0], _8area[0][1], _8area[0][2], _8area[1][2], _8area[2][2], _8area[2][1], _8area[2][0],
_8area[1][0]]
p = sorted(p1)
q = [abs(int(p[0]) - int(p[1])), abs(int(p[1]) - int(p[2])), abs(int(p[2]) - int(p[3])), abs(int(p[3]) - int(p[4])),
abs(int(p[4]) - int(p[5])), abs(int(p[5]) - int(p[6])), abs(int(p[6]) - int(p[7]))]
# 判断区分度
if max(q) < 10:
return result, False
max_index = q.index(max(q))
for i in range(0, max_index + 1):
result[p1.index(p[i])] = 1
for i in range(8):
if result[i] != 1:
result[i] = 2
return result, True
# 去除 del_num 号元素,del_num:0~7
def division2(_8area, del_num):
r = [0] * 8
p1 = [_8area[0][0], _8area[0][1], _8area[0][2], _8area[1][2], _8area[2][2], _8area[2][1], _8area[2][0],
_8area[1][0]]
p2 = []
for i in range(8):
if i == del_num:
continue
p2.append(p1[i])
result = [0] * 8
p = sorted(p2)
q = [abs(int(p[0]) - int(p[1])), abs(int(p[1]) - int(p[2])), abs(int(p[2]) - int(p[3])), abs(int(p[3]) - int(p[4])),
abs(int(p[4]) - int(p[5])), abs(int(p[5]) - int(p[6]))]
# 判断区分度
if max(q) < 10:
return result, False
max_index = q.index(max(q))
for i in range(0, max_index + 1):
result[p1.index(p[i])] = 1
for i in range(8):
if result[i] != 1:
result[i] = 2
result[del_num] = 0
return result, True
def noise_check(img_channel):
(row, col) = img_channel.shape
result = [[0] * col for i in range(row)]
for i in range(1, row - 1):
for j in range(1, col - 1):
# _8_area = type(img_channel)
_8_area = [[0] * 3 for i in range(3)]
_8_area[0][0] = img_channel[i - 1][j - 1]
_8_area[0][1] = img_channel[i - 1][j]
_8_area[0][2] = img_channel[i - 1][j + 1]
_8_area[1][2] = img_channel[i][j + 1]
_8_area[2][2] = img_channel[i + 1][j + 1]
_8_area[2][1] = img_channel[i + 1][j]
_8_area[2][0] = img_channel[i + 1][j - 1]
_8_area[1][0] = img_channel[i][j - 1]
# 不考虑位置
part1, flag1 = division1(_8_area)
# 如果在不去除点的情况下,不需要划分,那么就跳过
if not flag1:
continue
part2 = []
for k in range(7):
cnt = 0
part2, flag2 = division2(_8_area, k)
if not flag2:
if k == 0 or k == 7:
cnt += 1
else:
continue
# 比较
for m in range(8):
if part2[m] != 0 and part1[m] != part2[m]:
cnt += 1
if cnt >= 1:
x, y = _1d_2_2d(k)
result[i - 1 + x][j - 1 + y] += 1
# 处理特殊值
# sx, sy = special_check(_8_area)
# if sx != -1:
# result[i - 1 + sx][j - 1 + sy] += 1
return result
# 不考虑缩小二分之一图像
def mark(pixel_channel):
for i in range(pixel_channel.row):
for j in range(pixel_channel.col):
if pixel_channel.noise[i][j] >= threshold:
pixel_channel.channel[i][j] = find_best(pixel_channel, i, j)
return pixel_channel
# 找到最合适的值
def find_best(pixel_channel, x, y):
p = pixel_channel.channel[x][y]
# 建立领域列表
neighborhood = []
if pixel_channel.row > x - 1 >= 0 and pixel_channel.col > y - 1 >= 0 and pixel_channel.noise[x - 1][y - 1] < threshold:
neighborhood.append(pixel_channel.channel[x - 1][y - 1])
if pixel_channel.row > x - 1 >= 0 and pixel_channel.col > y >= 0 and pixel_channel.noise[x - 1][y] < threshold:
neighborhood.append(pixel_channel.channel[x - 1][y])
if pixel_channel.row > x - 1 >= 0 and pixel_channel.col > y + 1 >= 0 and pixel_channel.noise[x - 1][y + 1] < threshold:
neighborhood.append(pixel_channel.channel[x - 1][y + 1])
if pixel_channel.row > x >= 0 and pixel_channel.col > y + 1 >= 0 and pixel_channel.noise[x][y + 1] < threshold:
neighborhood.append(pixel_channel.channel[x][y + 1])
if pixel_channel.row > x + 1 >= 0 and pixel_channel.col > y + 1 >= 0 and pixel_channel.noise[x + 1][y + 1] < threshold:
neighborhood.append(pixel_channel.channel[x + 1][y + 1])
if pixel_channel.row > x + 1 >= 0 and pixel_channel.col > y >= 0 and pixel_channel.noise[x + 1][y] < threshold:
neighborhood.append(pixel_channel.channel[x + 1][y])
if pixel_channel.row > x + 1 >= 0 and pixel_channel.col > y - 1 >= 0 and pixel_channel.noise[x + 1][y - 1] < threshold:
neighborhood.append(pixel_channel.channel[x + 1][y - 1])
if pixel_channel.row > x >= 0 and pixel_channel.col > y - 1 >= 0 and pixel_channel.noise[x][y - 1] < threshold:
neighborhood.append(pixel_channel.channel[x][y - 1])
# 搜索与给定点最接近的非噪声点
# 建立差值列表
d = []
for i in range(len(neighborhood)):
d.append(abs(int(neighborhood[i]) - int(p)))
if len(d) == 0:
return p
min_index = d.index(min(d))
return neighborhood[min_index]
# 考虑缩小二分之一图像
def repair(pixel_channel, half_channel):
# 左上角
for i in range(half_channel[0].row):
for j in range(half_channel[0].col):
if half_channel[0].noise[i][j] >= threshold:
pixel_channel.noise[i * 2][j * 2] += half_channel[0].noise[i][j]
# 右上角
for i in range(half_channel[1].row):
for j in range(half_channel[1].col):
if half_channel[1].noise[i][j] >= threshold:
pixel_channel.noise[i * 2][j * 2 + 1] += half_channel[1].noise[i][j]
# 左下角
for i in range(half_channel[2].row):
for j in range(half_channel[2].col):
if half_channel[2].noise[i][j] >= threshold:
pixel_channel.noise[i * 2 + 1][j * 2] += half_channel[2].noise[i][j]
# 右下角
for i in range(half_channel[3].row):
for j in range(half_channel[3].col):
if half_channel[3].noise[i][j] >= threshold:
pixel_channel.noise[i * 2 + 1][j * 2 + 1] += half_channel[3].noise[i][j]
for i in range(pixel_channel.row):
for j in range(pixel_channel.col):
if pixel_channel.noise[i][j] >= threshold:
pixel_channel.channel[i][j] = find_best(pixel_channel, i, j)
return pixel_channel
def main():
# 图像地址
img_address = "img_noise.png"
# 以 BGR 方式读入图像
img = cv.imread(img_address, 1)
cv.imshow("img_noise.png", img)
# 通道分离
channel_b, channel_g, channel_r = cv.split(img)
# 建立像素通道类
b = create_pixel_channel(channel_b)
g = create_pixel_channel(channel_g)
r = create_pixel_channel(channel_r)
# 缩小二分之一
# half_b = [half_1(b), half_2(b), half_3(b), half_4(b)]
# half_g = [half_1(g), half_2(g), half_3(g), half_4(g)]
# half_r = [half_1(r), half_2(r), half_3(r), half_4(r)]
fp = open('b.noise.csv', 'w')
for i in range(b.row):
for j in range(b.col):
print(b.noise[i][j], file=fp, end='')
print(",", file=fp, end='')
print("", file=fp)
fp = open('b.pixel.csv', 'w')
for i in range(b.row):
for j in range(b.col):
print(b.channel[i][j], file=fp, end='')
print(",", file=fp, end='')
print("", file=fp)
# 不考虑二分之一图像
new_img = cv.merge((mark(b).channel, mark(g).channel, mark(r).channel))
# 考虑二分之一图像
# new_img = cv.merge((repair(b, half_b).channel, repair(g, half_g).channel, repair(r, half_r).channel))
cv.imwrite("denoised_img.png", new_img)
cv.imshow("denoised_img.png", new_img)
cv.waitKey()
cv.destroyAllWindows()
if __name__ == '__main__':
main()
正文完